package com.huabo.schedule;

import com.huabo.utils.FastJsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.matchers.GroupMatcher;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 任务调度管理器， 实现任务的动态操作
 * Created by Jackie Liu on 2017/8/2.
 */
public class ScheduleManager {

    //为调度管理器注入工厂bean
    private StdScheduler scheduler;

    //调度名称
    public static final String SCHEDULER_NAME = "huabo_scheduler";

    public StdScheduler getScheduler() {
        return scheduler;
    }

    public void setScheduler(StdScheduler scheduler) {
        this.scheduler = scheduler;
    }

    /**
     * 添加任务
     *
     * @param job
     * @throws SchedulerException
     */
    public void addJob(ScheduleJob job) throws SchedulerException, ClassNotFoundException {
        if (job == null || job.getJobId() == null) {
            return;
        }
        if (StringUtils.isEmpty(job.getCronExpression())
                && null == job.getSimpleExpression()) {
            return;
        }
        if (StringUtils.isEmpty(job.getJobClassName())) {
            return;
        }
        if (StringUtils.isEmpty(job.getJobName())) {
            job.setJobName(JobConstants.JobName.JOB_DEFAULT_NAME);
        }
        if (null == job.getSimpleExpression()) {
            addCronJob(job);
        } else {
            addSimpleJob(job);
        }
    }

    /**
     * 添加 cron 表达式任务
     *
     * @param job
     * @throws SchedulerException
     * @throws ClassNotFoundException
     */
    private void addCronJob(ScheduleJob job) throws SchedulerException, ClassNotFoundException {
        //根据任务id和任务组Id创建触发器key
        TriggerKey triggerKey = TriggerKey.triggerKey(String.valueOf(job.getJobId()), job.getJobGroup());
        //获取触发器对象
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        // 不存在，创建一个
        if (null == trigger) {
            JobDetail jobDetail = JobBuilder.newJob(job.isConcurrent() ? DefaultJobFactory.class : DisallowConcurrentJobFactory.class)
                    .withIdentity(String.valueOf(job.getJobId()), job.getJobGroup()).build();
            jobDetail.getJobDataMap().put(SCHEDULER_NAME, FastJsonUtils.objToJson(job));
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(
                            job.getCronExpression())).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } else {
            updateJobCron(job);
        }
    }

    /**
     * 添加 简单时间 表达式任务
     *
     * @param job
     * @throws SchedulerException
     * @throws ClassNotFoundException
     */
    private void addSimpleJob(ScheduleJob job) throws SchedulerException {
        //根据任务id和任务组Id创建触发器key
        TriggerKey triggerKey = TriggerKey.triggerKey(String.valueOf(job.getJobId()), job.getJobGroup());
        //获取触发器对象
        SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
        // 不存在，创建一个
        if (null == trigger) {
            JobDetail jobDetail = JobBuilder.newJob(job.isConcurrent() ? DefaultJobFactory.class : DisallowConcurrentJobFactory.class)
                    .withIdentity(String.valueOf(job.getJobId()), job.getJobGroup()).build();
            jobDetail.getJobDataMap().put(SCHEDULER_NAME, FastJsonUtils.objToJson(job));
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule())
                    .startAt(job.getSimpleExpression()).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } else {
            updateJobSimple(job);
        }
    }

    /**
     * 更新job时间表达式
     *
     * @param job
     * @throws SchedulerException
     */
    public void updateJobCron(ScheduleJob job) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(String.valueOf(job.getJobId()), job.getJobGroup());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 更新job时间表达式
     *
     * @param job
     * @throws SchedulerException
     */
    public void updateJobSimple(ScheduleJob job) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(String.valueOf(job.getJobId()), job.getJobGroup());
        SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(SimpleScheduleBuilder.simpleSchedule())
                .startAt(job.getSimpleExpression()).build();
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 获取所有计划中的任务列表
     *
     * @return
     * @throws SchedulerException
     **/
    public List<ScheduleJob> getAllJob() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                ScheduleJob job = new ScheduleJob();
                job.setJobId(Long.valueOf(jobKey.getName()));
                job.setJobGroup(jobKey.getGroup());
                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                job.setJobStatus(triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    job.setCronExpression(cronExpression);
                }
                jobList.add(job);
            }
        }
        return jobList;
    }

    /**
     * 所有正在运行的job
     *
     * @return
     * @throws SchedulerException
     */
    public List<ScheduleJob> getRunningJob() throws SchedulerException {
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        List<ScheduleJob> jobList = new ArrayList<>(executingJobs.size());
        for (JobExecutionContext executingJob : executingJobs) {
            ScheduleJob job = new ScheduleJob();
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            job.setJobName(jobKey.getName());
            job.setJobGroup(jobKey.getGroup());
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            job.setJobStatus(triggerState.name());
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                job.setCronExpression(cronExpression);
            }
            jobList.add(job);
        }
        return jobList;
    }

    /**
     * 暂停一个job
     *
     * @param scheduleJob
     * @throws SchedulerException
     */
    public void pauseJob(ScheduleJob scheduleJob) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(String.valueOf(scheduleJob.getJobId()), scheduleJob.getJobGroup());
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复一个job
     *
     * @param job
     * @throws SchedulerException
     */
    public void resumeJob(ScheduleJob job) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(String.valueOf(job.getJobId()), job.getJobGroup());
        scheduler.resumeJob(jobKey);
    }

    /**
     * 删除一个job
     *
     * @param scheduleJob
     * @throws SchedulerException
     */
    public void deleteJob(ScheduleJob scheduleJob) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(String.valueOf(scheduleJob.getJobId()), scheduleJob.getJobGroup());
        scheduler.deleteJob(jobKey);
    }

    /**
     * 立即执行job
     *
     * @param job
     * @throws SchedulerException
     */
    public void triggerJob(ScheduleJob job) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(String.valueOf(job.getJobId()), job.getJobGroup());
        scheduler.triggerJob(jobKey);
    }
}
